#pragma once
#include "cuboid.h"
#include <list>
#include <unordered_map>
enum class direction_set{FRONT,BACK,BOTTOM,BEYOND,LEFT,RIGHT};

//八叉树的节点也是一个长方体
class OctreeNode : public Cuboid{
public:
    OctreeNode(const Point& center, const float& halflength, const float& halfwidth, const float& halfheight);
    OctreeNode() = default;
    ~OctreeNode();
public:
    //指向父节点的指针
    OctreeNode* m_parent{nullptr};
    //指向子节点的指针数组
    OctreeNode* m_children[8];
    //包含在该节点中的所有场景点，链表的形式存储
    Point* m_scenepointslist{nullptr};
    //包含该节点中的所有障碍物点
    Point* m_obstaclepointslist{nullptr};
    //包含该节点中的所有未知属性的点,可以不直接放进八叉树，只是为了减少计算量
    std::list<Point*> m_noattributepointslist;
    //该八叉树节点的含有的总点数
    unsigned int m_pointnum;
    //位置码Mortan
    uint64_t MortanCode;
    //Children
    uint8_t  ChildExists; // optional
public:
    //构建一颗特定深度的八叉树
    static OctreeNode* BuildOctree(OctreeNode* parent,const Point& center, const float& halflength, const float& halfwidth, const float& halfheight, int stopDepth);
    //向八叉树中插入点
    static void InsertObjectToScene(OctreeNode* pTree, Point* pPoint);
    static void InsertObjectToObstacle(OctreeNode* pTree, Point* pPoint);
    static void InsertObjectTonoattribute(OctreeNode* pTree, Point* pPoint);
    //在八叉树中寻找点
    static OctreeNode* SearchPoint(OctreeNode* pTree, const Point* pPoint);
};

class Octree
{
public:
    Octree();
    OctreeNode* GetParentNode(OctreeNode* node);
    uint64_t NodeDepth(uint64_t MortanCode);
    void VisitAll(const OctreeNode* node);
    OctreeNode* BuildOctree(OctreeNode* parent,uint64_t MortanCode, const Point& center, const float& halflength, const float& halfwidth, const float& halfheight, int stopDepth);
    void InsertObject(OctreeNode* pTree, Point* pPoint,uint64_t MortanCode = 1);
    uint64_t SearchNodeByMortanCode(direction_set direction, uint64_t MortanCode, const Point* incidentpoint);
    uint64_t SearchNodeByPosition(uint64_t MortanCode,const Point* point);
    uint64_t SearchNodeByPositionFromRoot(const Point* point,uint64_t MortanCode = 1);
    OctreeNode* GetRoot();
    OctreeNode* LookupNode(uint64_t locCode);

public:
    std::unordered_map<uint64_t, OctreeNode*> Nodes;
};
